﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Web;

namespace EricWillis.Pop2Ticket.Unfuddle
{
    public class UnfuddleClient
    {
        #region Privates
        
        private String _username;
        private String _password;
        private String _subdomain;
        private String _projectID;
        private Boolean _useSsl;

        #endregion

        #region Properties

        /// <summary>
        /// Unfuddle username
        /// </summary>
        public String Username
        {
            get { return this._username; }
            set { this._username = value; }
        }

        /// <summary>
        /// Unfuddle password
        /// </summary>
        public String Password
        {
            get { return this._password; }
            set { this._password = value; }
        }

        /// <summary>
        /// Unfuddle subdomain (i.e. YOU.unfuddle.com)
        /// </summary>
        public String Subdomain
        {
            get { return this._subdomain; }
            set { this._subdomain = value; }
        }

        /// <summary>
        /// Unfuddle project ID
        /// </summary>
        public String ProjectID
        {
            get { return this._projectID; }
            set { this._projectID = value; }
        }

        /// <summary>
        /// Should use Ssl (based on project settings on http://unfuddle.com or personal preference)
        /// </summary>
        public Boolean UseSsl
        {
            get { return this._useSsl; }
            set { this._useSsl = value; }
        }

        /// <summary>
        /// Unfuddle account Uri based off of subdomain and Ssl values
        /// </summary>
        public Uri AccountUri
        {
            get
            {
                return new Uri(String.Format("{0}://{1}.unfuddle.com/",
                    this._useSsl ? "https" : "http", this._subdomain));
            }
        }

        /// <summary>
        /// Unfuddle project Uri based off of account Uri and project ID
        /// </summary>
        public Uri ProjectTicketsUri
        {
            get
            {
                return new Uri(String.Format("{0}api/v1/projects/{1}/tickets",
                    this.AccountUri.ToString(), this._projectID));
            }
        }

        #endregion

        #region Constructors
       
        /// <summary>
        /// Creates a new Unfuddle client
        /// </summary>
        /// <param name="username">Unfuddle username</param>
        /// <param name="password">Unfuddle password</param>
        /// <param name="subdomain">Unfuddle subdomain</param>
        /// <param name="projectID">Unfuddle project ID</param>
        public UnfuddleClient(String username, String password, String subdomain, String projectID)
            : this(username, password, subdomain, projectID, false)
        { }

        /// <summary>
        /// Creates a new Unfuddle client
        /// </summary>
        /// <param name="username">Unfuddle username</param>
        /// <param name="password">Unfuddle password</param>
        /// <param name="subdomain">Unfuddle subdomain</param>
        /// <param name="projectID">Unfuddle project ID</param>
        /// <param name="useSsl">Should use Ssl</param>
        public UnfuddleClient(String username, String password, String subdomain, String projectID, Boolean useSsl)
        {
            this._username = username;
            this._password = password;
            this._subdomain = subdomain;
            this._projectID = projectID;
            this._useSsl = useSsl;
        }

        #endregion

        #region Public Methods
        
        /// <summary>
        /// Add a new ticket
        /// </summary>
        /// <param name="priority">Priority of ticket</param>
        /// <param name="from">Ticket creator</param>
        /// <param name="summary">Summary of ticket (subject)</param>
        /// <param name="description">Description of ticket (in-depth)</param>
        /// <returns>Populated Unfuddle ticket</returns>
        public Ticket AddTicket(TicketPriority priority, String from, String summary, String description)
        {
            Ticket ticket = new Ticket(priority, summary, description);
            String body = String.Empty;

            // this Xml comes from http://unfuddle.com/docs/api/data_models#ticket
            body = String.Format("<ticket><priority>{0}</priority><summary>{1}</summary><description>From: {2}\n\n{3}</description></ticket>",
                (Int32)priority, HttpUtility.HtmlEncode(ticket.Summary), HttpUtility.HtmlEncode(from), 
                HttpUtility.HtmlEncode(ticket.Description));

            this.Post(this.ProjectTicketsUri, body);

            return ticket;
        }

        #endregion

        #region Private Methods
        
        /// <summary>
        /// Simple Http Post with body to specified Uri
        /// </summary>
        /// <param name="uri">Endpoint of Post action</param>
        /// <param name="body">Xml to send</param>
        /// <returns>Response of post from your-subdomain.unfuddle.com</returns>
        private String Post(Uri uri, String body)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            HttpWebResponse response = null;
            String value = String.Empty;

            try
            {
                request.ContentType = "application/xml";
                request.Method = "POST";
                // all Unfuddle requests must be authenticated
                request.Credentials = new NetworkCredential(this._username, this._password); ;

                if (!String.IsNullOrEmpty(body))
                {
                    Byte[] data = Encoding.UTF8.GetBytes(body);

                    request.ContentLength = data.Length;

                    using (Stream stream = request.GetRequestStream())
                    {
                        stream.Write(data, 0, data.Length);
                        stream.Flush();
                        stream.Close();
                    }
                }

                response = (HttpWebResponse)request.GetResponse();

                // read response from server so we can return it as a string
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                    value = reader.ReadToEnd();
            }

            catch (Exception ex)
            {
                // send any exceptions up but make sure we close the response stream (see: finally {})
                throw ex;
            }

            finally
            {
                if (response != null)
                    response.Close();
            }

            return value;
        }

        #endregion
    }
}
